package edu.ssdut.revise.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;

public class FileUtils {
    private final static Logger logger = LoggerFactory.getLogger(FileUtils.class);

    public static String getFileContent(String path) throws IOException {
        if (ifExistsAndFile(path)) {
            return Files.readString(Path.of(path)); // TODO might have encoding issues?
        } else {
            logger.warn("illegal pathString: " + path + " encountered");
            return "";
        }
    }

    /**
     * Check if the given File exists and represents a directory.
     */
    public static Boolean ifExistsAndDirectory(File f) {
        if (f == null) {
            logger.info("NULL POINTER ENCOUNTERED");
            return false;
        }
        if (!f.exists()) {
            logger.info("FILE NOT EXISTS: " + f.getAbsolutePath());
            return false;
        }
        if (!f.isDirectory()) {
            logger.info("FILE NOT A DIRECTORY: " + f.getAbsolutePath());
            return false;
        }
        return true;
    }

    public static Boolean ifExistsAndDirectory(String path) {
        File f = new File(path);
        return ifExistsAndDirectory(f);
    }

    /**
     * Check if the given File exists and represents a file rather than a directory.
     *
     * @throws IOException If an I/O error occurs, which is possible because the construction of the canonical pathname may require filesystem queries
     */
    public static Boolean ifExistsAndFile(File f) throws IOException {
        if (f == null) {
            logger.info("NULL POINTER ENCOUNTERED");
            return false;
        }
        if (!f.exists()) {
            logger.info("FILE NOT EXISTS: " + f.getCanonicalPath());
            return false;
        }
        if (f.isDirectory()) {
            logger.info(f.getCanonicalPath() + " FILE NOT A FILE: ");
            return false;
        }
        return true;
    }

    public static Boolean ifExistsAndFile(String path) throws IOException {
        File f = new File(path);
        return ifExistsAndFile(f);
    }

    /**
     * get all files that are not directories under the given directory
     */
    public static List<File> getAllFilesUnder(File rootDir) {
        List<File> ret = new LinkedList<>();
        if (!ifExistsAndDirectory(rootDir)) {
            return ret; // not a dir, return empty
        }
        // exists and is directory
        recursiveGetFileUnder(rootDir, ret);
        return ret;
    }

    /**
     * test if the given file is a java source file
     */
    public static Boolean isJavaFile(File f) {
        return f.getName().endsWith(".java");
    }

    /**
     * test if the given fileName is a java source file
     *
     * @return if the input file ends with <code><b>.java</b></code>
     */
    public static Boolean isJavaFile(String fileName) {
        return fileName.endsWith(".java");
    }

    /**
     * recursively get all files under a given directory and add them into a flattened list
     *
     * @param dir  the given directory
     * @param list the list used to store all files
     */
    private static void recursiveGetFileUnder(File dir, List<File> list) {
        for (File f : Objects.requireNonNull(dir.listFiles())) {
            if (f.isDirectory()) {
                recursiveGetFileUnder(f, list);
            } else {
                list.add(f);
            }
        }
    }
}
